package org.luo.lan.server.handlers;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.internal.AppendableCharSequence;
import lombok.extern.slf4j.Slf4j;
import org.luo.lan.common.util.StringUtils;
import org.luo.lan.server.factory.BridgeChannelFactory;
import org.luo.lan.server.util.HostReplaceInfo;
import org.luo.lan.server.util.HttpHeaderParser;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class DomainServerHandler extends AbstractServerHandler {
    private final String HTTP_HOST_HEADER_PREFIX = "Host:";
    private ThreadLocal<HostReplaceInfo> HOST_INDEX_LENGTH = new ThreadLocal<>();

    @Override
    String getProxyKey(ChannelHandlerContext ctx,ByteBuf byteBuf) {
        ByteBuf sliceByteBuf=byteBuf.slice(0, byteBuf.readableBytes());
        String host=getHost(sliceByteBuf);
        return host;
    }

    @Override
    byte[] getBytes(ByteBuf byteBuf) {
        ByteBuf byteBuf1=byteBuf.copy();
        byte[] temp = new byte[byteBuf1.readableBytes()];
        byteBuf1.readBytes(temp);
        byte[] bytes;
        HostReplaceInfo hostReplaceInfo= HOST_INDEX_LENGTH.get();
        if (hostReplaceInfo != null ) {
            String oldTarget=hostReplaceInfo.getOldTarget();
            String newTarget=hostReplaceInfo.getNewTarget();
            int startIndex=hostReplaceInfo.getHostStartIndex();
            byte[] b1 = new byte[startIndex];
            byteBuf.readBytes(b1);
            byte[] b2 = newTarget.getBytes();
            byteBuf.setIndex((startIndex + oldTarget.length()),byteBuf.writerIndex());
            byte[] b3 = new byte[byteBuf.readableBytes()];
            byteBuf.readBytes(b3);
            bytes = new byte[b1.length+b2.length+b3.length];
            System.arraycopy(b1, 0, bytes, 0,b1.length);
            System.arraycopy(b2, 0, bytes, b1.length,b2.length);
            System.arraycopy(b3, 0, bytes, b1.length+b2.length,b3.length);
        }else{
            bytes = new byte[byteBuf.readableBytes()];
            byteBuf.readBytes(bytes);
        }
        return bytes;
    }


    private String getHost(ByteBuf sliceByteBuf){
        HOST_INDEX_LENGTH.set(null);
        AppendableCharSequence seq=new AppendableCharSequence(128);
        HttpHeaderParser headerParser = new HttpHeaderParser(seq,8192);
        AppendableCharSequence line = headerParser.parse(sliceByteBuf);
        if (line == null) {
            return null;
        }
        String host = "";
        do {
            line = headerParser.parse(sliceByteBuf);
            if (line == null) {
                break;
            }
            if (line.length() > HTTP_HOST_HEADER_PREFIX.length()&&line.substring(0,HTTP_HOST_HEADER_PREFIX.length()).equalsIgnoreCase(HTTP_HOST_HEADER_PREFIX)) {
                String host_port=line.substring(5,line.length());
                host = host_port.trim().split(":")[0];
                String target=BridgeChannelFactory.INSTANCE.getTarget(host);
                if (StringUtils.isNotBlank(target) && !isIp(target.split(":")[0])) {
                    HOST_INDEX_LENGTH.set(new HostReplaceInfo(sliceByteBuf.readerIndex()-host_port.length()-2,host_port,target));
                }
                break;
            }
        } while (line.length() > 0);
        return  host;
    }

    private boolean isIp(String host) {
        String pattern = "(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)";
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(host);
        return m.matches();

    }

}
